﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;


using System.Text.RegularExpressions;

using System.Diagnostics;

using Scheduler;
using CoursePack;
using ScheduleGrid;


namespace WindowsFormsApplication2.Forms
{
    public partial class ScheduleViewer : Form
    {
        #region Data

        private ScheduleManager m_Scheduler;
        private BackgroundWorker worker;
        private Student m_Student;
        #endregion

        public ScheduleViewer(Student _Student)
        {
            InitializeComponent();
            this.m_Student = _Student;



            this.m_Scheduler = new ScheduleManager(dayView1.StartDate, _Student, this.dayView1);

            this.splitContainer3.Panel2.BackColor = System.Drawing.Color.FromArgb(230, 237, 247);
            this.rdWinter.Tag = "Winter";
            this.rdSummer.Tag = "Summer";
            this.rdFall.Tag = "Fall";
        }

        #region DayView Methods


        private void dayView1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
                if (dayView1.SelectedAppointment != null)
                {
                    this.m_Scheduler.RemoveAppointment(dayView1.SelectedAppointment);
                    dayView1.Invalidate();
                }
        }


        private void dayView1_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {

                TimeConstraint constraint = new TimeConstraint(this.dayView1.SelectionStart.TimeOfDay, this.dayView1.SelectionEnd.TimeOfDay, dayView1.SelectionStart.DayOfWeek);

                this.m_Scheduler.AddConstraint(constraint);
                this.dayView1.SelectionStart = new DateTime();
                this.dayView1.SelectionEnd = new DateTime();

                this.m_Scheduler.DisplayAppointements();

            }
        }


        #endregion

        #region TreeView with Courses
        private void treeView1_AfterExpand(object sender, TreeViewEventArgs e)
        {
            Course _Course = (Course)e.Node.Tag;


            if ((Course)e.Node.Tag != null)
            {

                if (this.m_Scheduler.CurrentSchedule.AddCourse(_Course))
                {


                    dayView1.Invalidate();

                    Rectangle rec = e.Node.Parent.Bounds;

                    rec.X -= 15;

                    this.treeView1.Invalidate(rec);

                }
            }
        }

        private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            Course _Course = (Course)e.Node.Tag;

            if (_Course != null)
                if ((this.m_Scheduler.CurrentSchedule.IsFull) && (e.Node.Text == _Course.Lecture.ToString()))
                {
                    e.Cancel = true;
                    MessageBox.Show("You have reached the number of courses you can take in a single semester. Please remove one or more class in order to add this one.", "Maximum number of courses");

                }
        }

        private void treeView1_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
        {
            Course _Course = (Course)e.Node.Tag;

            if ((_Course != null) && (e.Node.Text == _Course.Lecture.ToString()))
            {

                if (this.m_Scheduler.CurrentSchedule.RemoveCourse(_Course))
                {
                    dayView1.Invalidate();

                    Rectangle rec = e.Node.Parent.Bounds;

                    rec.X -= 15;

                    this.treeView1.Invalidate(rec);
                }

            }
            else
            {
                foreach (TreeNode course in e.Node.Nodes)
                {
                    Course cc = (Course)course.Tag;

                    if (this.m_Scheduler.CurrentSchedule.RemoveCourse(cc))
                    {
                        dayView1.Invalidate();
                        e.Node.Collapse();
                        break;
                    }

                }

            }
        }

        private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
        {

            Course course = (Course)e.Node.Tag;
            bool InSchedule = false;

            if (e.Node.Parent == null)
                foreach (TreeNode cc in e.Node.Nodes)
                {
                    if (this.m_Scheduler.CurrentSchedule.IsCourseIn((Course)cc.Tag))
                        InSchedule = true;
                }

            bool isOSDrawn = e.DrawDefault;
            Graphics g = e.Graphics;
            TreeNode tn = e.Node;
            Font DrawFont = treeView1.Font;
            Brush ForeBrush = new SolidBrush(Color.Black);
            Brush BackGroundBrush = new SolidBrush(e.Node.BackColor);

            Brush TextBackGroundBrush = BackGroundBrush;
            float baseX = e.Bounds.Left;
            float baseY = e.Bounds.Top;
            string stringToDraw = tn.Text;
            bool hasParent = (tn.Parent != null);
            bool hasNext = (tn.NextNode != null);
            bool hasPrev = (tn.PrevNode != null);

            float strX = baseX;
            float strY = baseY;
            float adjX = ((tn.Level + 1) * 24);
            strX += adjX;

            Rectangle UpLine = new Rectangle((int)(strX - 17), (int)(baseY), 2, 8);
            Rectangle DownLine = new Rectangle((int)(strX - 17), (int)(baseY + 8), 2, 8);
            Rectangle ChildBox = new Rectangle((int)(baseX - 16 + adjX + 2), (int)(baseY + 2), 12, 12);

            float tailStartX = baseX - 16 + adjX + 2 + 12;
            float tailStartY = baseY + 8;
            if (e.Bounds.Width != 0)
            {
                if ((e.State & TreeNodeStates.Hot) == TreeNodeStates.Hot)
                {//Hot tracking
                    DrawFont = new Font(DrawFont, FontStyle.Underline);
                }
                if ((e.State & TreeNodeStates.Selected) == TreeNodeStates.Selected)
                {//change foregroudn/background
                    TextBackGroundBrush = new SolidBrush(SystemColors.InactiveBorder);
                    if (this.ActiveControl == sender)
                    {
                        ForeBrush = new SolidBrush(SystemColors.HighlightText);
                        TextBackGroundBrush = new SolidBrush(SystemColors.Highlight);
                    }
                }
                //// Erase previous
                g.FillRectangle(BackGroundBrush, e.Bounds);
                SizeF stringSize = g.MeasureString(stringToDraw, DrawFont, (int)(e.Bounds.Width - strX), new StringFormat(StringFormatFlags.NoWrap));
                //// Draw the "selected" background
                g.FillRectangle(TextBackGroundBrush, strX, strY, (float)Math.Floor(stringSize.Width), 16F);
                //// Draw the text
                g.DrawString(stringToDraw, DrawFont, ForeBrush, strX, strY);

                //// Every node gets a tail sticking out
                g.FillRectangle(Brushes.Black, strX - 17, tailStartY, 16, 2);
                ///////////////////////////////////////////////////////////////////
                if (hasPrev || hasParent) g.FillRectangle(Brushes.Black, UpLine);// Draw up line
                if (hasNext) g.FillRectangle(Brushes.Black, DownLine);// Draw down line
                //// Draw the "+" box
                if (tn.Nodes.Count > 0)
                {
                    if (InSchedule)
                        g.FillRectangle(new SolidBrush(Color.BlueViolet), ChildBox);

                    if (e.Node.Parent != null)
                        g.FillRectangle(new SolidBrush(Color.BlueViolet), ChildBox);

                    if (!tn.IsExpanded)
                        g.FillRectangle(new SolidBrush(Color.Red), ChildBox);

                    g.DrawRectangle(Pens.Black, ChildBox);
                }

            }//end of valid draw region

        }

        private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (((Course)e.Node.Tag != null) && (e.Node.Nodes.Count == 0))
            {
                Course _Course = (Course)e.Node.Tag;

                if (this.m_Scheduler.CurrentSchedule.AddCourse(_Course))
                {
                    this.m_Scheduler.DisplayAppointements();
                }
            }

            Course _Cc = (Course)e.Node.Tag;
            if (_Cc != null)
            {
                this.lblClarityN.Text = "";
                this.lblEasinessN.Text = "";
                this.lblHelpfulnessN.Text = "";
                this.lblOveralN.Text = "";

                // Tell the worker to report progress.
                this.lblTitle.Text = _Cc.CourseName + " " + _Cc.CourseNumber + " - " + _Cc.CourseTitle;

                worker = new BackgroundWorker();

                worker.WorkerReportsProgress = true;

                worker.DoWork += DoWork;
                worker.RunWorkerAsync(_Cc);

                this.lblProf.Text = _Cc.Lecture.Professor;
                this.lblPrereq.Text = _Cc.Prerequisite;
                this.boxSpecialNotes.Text = _Cc.SpecialNotes;
                this.lblOveralN.Left = this.lblProf.Left + this.lblProf.Width + 10;
                this.lblOverall.Left = this.lblOveralN.Left;

                this.lblHelpfulnessN.Left = this.lblOveralN.Left + this.lblOveralN.Width + 10;
                this.lblHelpfulness.Left = this.lblHelpfulnessN.Left;

                this.lblClarityN.Left = this.lblHelpfulnessN.Left + this.lblHelpfulnessN.Width + 10;
                this.lblClarity.Left = this.lblClarityN.Left;


                this.lblEasinessN.Left = this.lblClarityN.Left + this.lblClarityN.Width + 10;
                this.lblEasiness.Left = this.lblEasinessN.Left;



            }

        }

        /// <summary>
        /// Load the treeview component with courses
        /// </summary>
        /// <param name="_Session"></param>
        private void LoadSessionCourses(string _Session)
        {
            #region Loading Courses
            ESession session;

            if (this.rdFall.Checked)
                session = ESession.Fall;
            else if (this.rdSummer.Checked)
                session = ESession.Summer;
            else
                session = ESession.Winter;

            List<Course> Courses = new List<Course>();

            System.IO.StreamReader file = new System.IO.StreamReader(
                + this.m_Student.Degree.Department.Faculty.Id + "\\"
                + this.m_Student.Degree.Department.Id + "\\"
                + session.ToString()
                + "2013"
                + ".txt");

            this.treeView1.SelectedNode = null;
            file.ReadLine();
            file.ReadLine();
            file.ReadLine();
            string line;

            int j = 0;
            while ((line = file.ReadLine()) != null)
            {

                j++;
                string[] tab = line.Split('|');

                for (int i = 0; i < tab.Length; i++)
                {
                    tab[i] = tab[i].Trim();
                }


                Class Lecture = new Class(ClassType.Lecture, tab[3], tab[4], tab[5], tab[6], tab[7], tab[8]);
                Class Tutorial = null, Lab = null;

                if (tab[9] != "")
                    Tutorial = new Class(ClassType.Tutorial, tab[9], tab[10], tab[11], tab[12], tab[13]);

                if (tab[14] != "")
                    Lab = new Class(ClassType.Lab, tab[14], tab[15], tab[16], tab[17], tab[18]);

                Course course = new Course(tab[0], tab[1], tab[2], Lecture, Tutorial, Lab, tab[19], tab[20], tab[21], tab[22], CourseStatus.NotStarted);
                Courses.Add(course);
            }

            TreeNode CourseNode = new TreeNode(Courses[0].ToString());


            TreeNode TutorialN, LabN, LectureN;

            this.treeView1.Nodes.Clear();

            foreach (Course course in Courses)
            {
                j++;
                string str1 = CourseNode.Text;
                string str2 = course.ToString();
                if (str1 != str2)
                {
                    CourseNode = new TreeNode(course.ToString());
                    this.treeView1.Nodes.Add(CourseNode);
                }

                LectureN = new TreeNode(course.Lecture.ToString());
                LectureN.Tag = course;

                CourseNode.Nodes.Add(LectureN);


                if (course.HasTutorial)
                {
                    TutorialN = new TreeNode(course.Tutorial.ToString());
                    TutorialN.Tag = course;

                    if (course.HasLab)
                    {
                        LabN = new TreeNode(course.Lab.ToString());
                        LabN.Tag = course;
                        TutorialN.Nodes.Add(LabN);
                        LectureN.Nodes.Add(TutorialN);


                    }
                    else
                    {
                        LectureN.Nodes.Add(TutorialN);
                    }
                }
                else if (course.HasLab)
                {
                    LabN = new TreeNode(course.Lab.ToString());
                    LabN.Tag = course;
                    LectureN.Nodes.Add(LabN);
                }
            }
            this.treeView1.Enabled = true;
            file.Close();
            #endregion

            DataTable dttable = new DataTable();

            DataColumn column = new DataColumn();
            column.DataType = System.Type.GetType("System.String");
            column.ColumnName = "Course";
            dttable.Columns.Add(column);

            column = new DataColumn();
            column.DataType = System.Type.GetType("System.String");
            column.ColumnName = "Credits";
            dttable.Columns.Add(column);

            List<CourseDescription> tmp = this.m_Student.Degree.CourseSequence.CourseInSemester(1, (ESession)Enum.Parse(typeof(ESession), _Session));
            if (tmp != null)

                foreach (CourseDescription cc in tmp)
                {
                    DataRow row = dttable.NewRow();

                    row["Credits"] = cc.Credits;
                    row["Course"] = cc.CourseName + " " + cc.CourseNumber;

                    dttable.Rows.Add(row);

                }

            this.dataGridView1.DataSource = dttable;
        }

        #endregion

        #region Radio Button Methods
        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            RadioButton radio = (RadioButton)sender;

            this.LoadSessionCourses((string)radio.Tag);
        }

        #endregion

        #region Tab Pages Methods
        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {
            this.dayView1.HalfHourHeight = (int)numericUpDown1.Value;
        }
        #endregion

        #region Form methods
        private void ScheduleViewer_Load(object sender, EventArgs e)
        {
            switch (ESession.Winter/*this.m_Student.Degree.GetSemester(new Session(1,ESession.Winter)).Session*/)
            {
                case ESession.Summer:
                    this.rdSummer.Checked = true;
                    break;
                case ESession.Winter:
                    this.rdWinter.Checked = true;
                    break;
                case ESession.Fall:
                    this.rdFall.Checked = true;
                    break;
            }
        }
        #endregion

        #region BackgroundWorker procedures RATE MY PROFESSOR
        public delegate void UpdateTextCallback(RateMyProfessorResponse profRating);

        /// <summary>
        /// The work for the BackgroundWorker to perform.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void DoWork(object sender, DoWorkEventArgs e)
        {
            RateMyProfessorResponse rating = RateMyProfessor.GetProfessorRating((Course)e.Argument);

            this.lblTitle.BeginInvoke(new UpdateTextCallback(this.ratemyprof),
                rating);

        }

        private void ratemyprof(RateMyProfessorResponse rating)
        {

            if (rating.IsRatingAvailable)
            {
                string clarity = rating.Clarity;
                string helpfulness = rating.Helpfulness;
                string overall = rating.Overall;
                string easy = rating.Easiness;

                this.lblClarityN.Text = clarity;
                this.lblEasinessN.Text = easy;
                this.lblHelpfulnessN.Text = helpfulness;
                this.lblOveralN.Text = overall;

            }
            else
            {
                this.lblClarityN.Text = "N/A";
                this.lblEasinessN.Text = "N/A";
                this.lblHelpfulnessN.Text = "N/A";
                this.lblOveralN.Text = "N/A";
            }
        }

        #endregion

        #region Buttons Methods
        /// <summary>
        /// Add CourseChoice to the list to generate schedule
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void vistaButton1_Click(object sender, EventArgs e)
        {
            if (this.treeView1.SelectedNode != null)
            {
                UserControls.CourseChoice courseChoice = new UserControls.CourseChoice(this.treeView1.SelectedNode);
                courseChoice.OnRemoveCourse += courseChoice_OnRemoveCourse;

                this.m_Scheduler.AddCoursesNode(courseChoice.Courses);

                courseChoice.Size = new Size(this.flowLayoutPanel1.Width - 8, courseChoice.Size.Height);

                this.flowLayoutPanel1.Controls.Add(courseChoice);
            }
        }


        private void courseChoice_OnRemoveCourse(object sender, EventArgs e)
        {
            ((UserControls.CourseChoice)sender).OnRemoveCourse -= courseChoice_OnRemoveCourse;

            this.m_Scheduler.RemoveCoursesNode(((UserControls.CourseChoice)sender).Courses);

            this.flowLayoutPanel1.Controls.Remove((Control)sender);
        }

        /// <summary>
        /// Generate schedule based on added constraint
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnGenerateSchedule_Click_1(object sender, EventArgs e)
        {
            this.m_Scheduler.Generate();
            this.m_Scheduler.DisplayAppointements();

        }

        #endregion

        private void vistaButton2_Click(object sender, EventArgs e)
        {
            this.m_Scheduler.Next();
        }

        private void vistaButton3_Click(object sender, EventArgs e)
        {
           
        }
    }
}
    
